package top.lingkang.fas.admin.utils;

import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Redisson操作工具类，采用静态方法实现，初始化后无需检查RedissonClient
 */
public final class RedissonUtil {
    private static final String LOCK_KEY_PREFIX = "lock:";
    private static RedissonClient redissonClient;
    private static boolean initialized = false;

    private RedissonUtil() {
        // 私有构造函数，防止实例化
    }

    /**
     * 初始化RedissonClient，必须在使用前调用
     *
     * @param client RedissonClient实例，不可为null
     * @throws IllegalArgumentException 如果client为null
     */
    public static synchronized void initialize(RedissonClient client) {
        if (client == null) {
            throw new IllegalArgumentException("RedissonClient cannot be null");
        }
        if (!initialized) {
            redissonClient = client;
            initialized = true;
        }
    }

    // ====================== 通用操作 ======================

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return 是否存在
     */
    public static boolean exists(String key) {
        return redissonClient.getKeys().countExists(key) > 0;
    }

    /**
     * 删除单个key
     *
     * @param key 键
     * @return 是否删除成功
     */
    public static boolean delete(String key) {
        return redissonClient.getKeys().delete(key) > 0;
    }

    /**
     * 批量删除key
     *
     * @param keys 键集合
     * @return 删除数量
     */
    public static long delete(List<String> keys) {
        return redissonClient.getKeys().delete(keys.toArray(new String[0]));
    }

    /**
     * 设置key的过期时间
     *
     * @param key     键
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return 是否设置成功
     */
    public static boolean expire(String key, long timeout, TimeUnit unit) {
        return redissonClient.getBucket(key).expire(timeout, unit);
    }

    // ====================== String 操作 ======================

    /**
     * 获取字符串值
     *
     * @param key 键
     * @return 值
     */
    public static <T> T get(String key) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        return bucket.get();
    }

    /**
     * 设置字符串值
     *
     * @param key   键
     * @param value 值
     */
    public static <T> void set(String key, T value) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value);
    }

    /**
     * 设置字符串值并带过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 超时时间
     * @param unit    时间单位
     */
    public static <T> void set(String key, T value, long timeout, TimeUnit unit) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value, timeout, unit);
    }

    // ====================== Hash 操作 ======================

    /**
     * 获取Hash结构中的值
     *
     * @param key   键
     * @param field 字段
     * @return 值
     */
    public static <K, V> V hget(String key, K field) {
        RMap<K, V> map = redissonClient.getMap(key);
        return map.get(field);
    }

    /**
     * 设置Hash结构中的值
     *
     * @param key   键
     * @param field 字段
     * @param value 值
     */
    public static <K, V> void hset(String key, K field, V value) {
        RMap<K, V> map = redissonClient.getMap(key);
        map.put(field, value);
    }

    /**
     * 获取整个Hash结构
     *
     * @param key 键
     * @return Map对象
     */
    public static <K, V> Map<K, V> hgetAll(String key) {
        RMap<K, V> map = redissonClient.getMap(key);
        return map.readAllMap();
    }

    // ====================== List 操作 ======================

    /**
     * 获取List结构中的元素
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置
     * @return 元素列表
     */
    public static <V> List<V> lrange(String key, int start, int end) {
        RList<V> list = redissonClient.getList(key);
        return list.range(start, end);
    }

    /**
     * 在List头部添加元素
     *
     * @param key    键
     * @param values 元素
     * @return 添加后的长度
     */
    public static <V> long lpush(String key, V... values) {
        RList<V> list = redissonClient.getList(key);
        list.addAll(0, List.of(values));
        return list.size();
    }

    /**
     * 在List尾部添加元素
     *
     * @param key    键
     * @param values 元素
     * @return 添加后的长度
     */
    public static <V> long rpush(String key, V... values) {
        RList<V> list = redissonClient.getList(key);
        list.addAll(List.of(values));
        return list.size();
    }

    // ====================== Set 操作 ======================

    /**
     * 获取Set结构中的所有元素
     *
     * @param key 键
     * @return 元素集合
     */
    public static <V> java.util.Set<V> smembers(String key) {
        RSet<V> set = redissonClient.getSet(key);
        return set.readAll();
    }

    /**
     * 向Set结构中添加元素
     *
     * @param key    键
     * @param values 元素
     * @return 添加成功的数量
     */
    public static <V> long sadd(String key, V... values) {
        RSet<V> set = redissonClient.getSet(key);
        long count = 0;
        for (V value : values) {
            if (set.add(value)) {
                count++;
            }
        }
        return count;
    }

    // ====================== 分布式锁操作 ======================

    /**
     * 获取分布式锁（可重入锁）
     *
     * @param lockKey 锁的键
     * @return RLock对象
     */
    public static RLock getLock(String lockKey) {
        return redissonClient.getLock(LOCK_KEY_PREFIX + lockKey);
    }

    /**
     * 加锁（阻塞等待，默认30秒自动释放）
     *
     * @param lockKey 锁的键
     * @return RLock对象
     */
    public static RLock lock(String lockKey) {
        RLock lock = getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 加锁并设置自动释放时间
     *
     * @param lockKey   锁的键
     * @param leaseTime 自动释放时间
     * @param unit      时间单位
     * @return RLock对象
     */
    public static RLock lock(String lockKey, long leaseTime, TimeUnit unit) {
        RLock lock = getLock(lockKey);
        lock.lock(leaseTime, unit);
        return lock;
    }

    /**
     * 尝试加锁
     *
     * @param lockKey   锁的键
     * @param waitTime  等待时间
     * @param leaseTime 自动释放时间
     * @param unit      时间单位
     * @return 是否成功获取锁
     */
    public static boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
        RLock lock = getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 释放锁
     *
     * @param lockKey 锁的键
     */
    public static void unlock(String lockKey) {
        RLock lock = getLock(lockKey);
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    // ====================== 关闭客户端 ======================

    /**
     * 关闭Redisson客户端连接
     */
    public static void shutdown() {
        if (redissonClient != null && !redissonClient.isShutdown()) {
            redissonClient.shutdown();
        }
    }
}